// EMERGENT GAME TECHNOLOGIES PROPRIETARY INFORMATION
//
// This software is supplied under the terms of a license agreement or
// nondisclosure agreement with Emergent Game Technologies and may not 
// be copied or disclosed except in accordance with the terms of that 
// agreement.
//
//      Copyright (c) 1996-2008 Emergent Game Technologies.
//      All Rights Reserved.
//
// Emergent Game Technologies, Chapel Hill, North Carolina 27517
// http://www.emergent.net

//---------------------------------------------------------------------------

template <class T> inline
GnTObjectList<T>::~GnTObjectList()
{
    // RemoveAll is called from here because it depends on virtual functions
    // implemented in GnTAllocatorMap.  It will also be called in the 
    // parent destructor, but the map will already be empty.
    GnTObjectList<T>::RemoveAll();
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::AddNewHead()
{
    GnTListItem<T>* pkNode;
    pkNode = (GnTListItem<T>*) NewItem();
    
    AddNodeHead(pkNode);

    return &pkNode->m_element;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::AddNewTail()
{
    GnTListItem<T>* pkNode;
    pkNode = (GnTListItem<T>*) NewItem();

    AddNodeTail(pkNode);

    return &pkNode->m_element;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::InsertNewBefore(GnTListIterator kPos, 
    GnTListIterator& kNewIterator)
{
    GnTListItem<T>* pkNode;
    pkNode = (GnTListItem<T>*) NewItem();

    kNewIterator = AddNodeBefore(kPos,pkNode);

    return &pkNode->m_element;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::InsertNewAfter(GnTListIterator kPos, 
    GnTListIterator& kNewIterator)
{
    GnTListItem<T>* pkNode;
    pkNode = (GnTListItem<T>*) NewItem();

    kNewIterator = AddNodeAfter(kPos,pkNode);

    return &pkNode->m_element;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::InsertNewBefore(GnTListIterator kPos)
{
    GnTListItem<T>* pkNode;
    pkNode = (GnTListItem<T>*) NewItem();

    AddNodeBefore(kPos,pkNode);

    return &pkNode->m_element;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::InsertNewAfter(GnTListIterator kPos)
{
    GnTListItem<T>* pkNode;
    pkNode = (GnTListItem<T>*) NewItem();
    
    AddNodeAfter(kPos,pkNode);

    return &pkNode->m_element;
}//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::GetHead() const
{
    return GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead ? 
        &GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead->m_element : NULL;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::GetTail() const
{
    return GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail ?
        &GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail->m_element : NULL;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::GetNext(GnTListIterator& kPos) const 
{
    if (kPos == 0)
        return NULL;

    T* pkElement = &((GnTListItem<T>*) kPos)->m_element;
    kPos = ((GnTListItem<T>*) kPos)->m_pkNext;
    return pkElement;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::GetPrev(GnTListIterator& kPos) const
{
    if (kPos == 0)
        return NULL;

    T* pkElement = &((GnTListItem<T>*) kPos)->m_element;
    kPos = ((GnTListItem<T>*) kPos)->m_pkPrev;
    return pkElement;
}
//---------------------------------------------------------------------------
template <class T> inline
T* GnTObjectList<T>::Get(GnTListIterator kPos) const
{
    if (!kPos)
        return NULL;
    
    return &((GnTListItem<T>*) kPos)->m_element;
}
//---------------------------------------------------------------------------
template <class T> inline
void GnTObjectList<T>::RemoveHead()
{
    GnAssert((GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead));

    GnTListItem<T>* pkNode = GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead;

    GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead = 
        GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead->m_pkNext;
    
    if (GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead)
        GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead->m_pkPrev = 0;
    else
        GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail = 0;
    
    DeleteItem(pkNode);

    GnTListBase<GnTObjectAllocator<T>, T>::m_kAllocator.m_uiCount--;
}
//---------------------------------------------------------------------------
template <class T> inline
void GnTObjectList<T>::RemoveTail()
{
    GnAssert((GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail));
    
    GnTListItem<T>* pkNode = GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail;

    GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail =
        GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail->m_pkPrev;
    
    if (GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail)
        GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail->m_pkNext = 0;
    else
        GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead = 0;
    
    DeleteItem(pkNode);

    GnTListBase<GnTObjectAllocator<T>, T>::m_kAllocator.m_uiCount--;
}
//---------------------------------------------------------------------------
template <class T> inline
void GnTObjectList<T>::RemovePos(GnTListIterator& kPos)
{
    GnTListItem<T>* pkNode = (GnTListItem<T>*) kPos;

    GnAssert(pkNode);

    if (pkNode == GnTListBase<GnTObjectAllocator<T>, T>::m_pkHead)
    {
        kPos = pkNode->m_pkNext; // kPos points to new head
        RemoveHead();
        
    }
    else if (pkNode == GnTListBase<GnTObjectAllocator<T>, T>::m_pkTail)
    {
        kPos = 0; // kPos has walked off end of list
        RemoveTail();
    }
    else
    {
        GnTListItem<T>* pkPrev = pkNode->m_pkPrev;
        GnTListItem<T>* pkNext = pkNode->m_pkNext;

        kPos = pkNext;
    
        if (pkPrev)
            pkPrev->m_pkNext = pkNext;
        if (pkNext)
            pkNext->m_pkPrev = pkPrev;
        
        DeleteItem(pkNode);
    
        GnTListBase<GnTObjectAllocator<T>, T>::m_kAllocator.m_uiCount--;
    }
}
//---------------------------------------------------------------------------
template <class T> inline
void GnTObjectList<T>::Remove(const T* element)
{
    GnTListIterator kPos = FindPos(element);
    if (kPos)
        RemovePos(kPos);
}
//---------------------------------------------------------------------------
template <class T> inline
GnTListIterator GnTObjectList<T>::FindPos(const T* element, 
    GnTListIterator kStart) const
{
    if (kStart == 0)
        kStart = GnTObjectList<T>::GetHeadPos();
    
    while (kStart)
    {
        GnTListIterator kPos = kStart;
        if (element == GetNext(kStart))
            return kPos;
    }
    return 0;
}       
//---------------------------------------------------------------------------
template <class T> inline
GnTListItem<T>* GnTObjectList<T>::NewItem()
{
    return (GnTListItem<T>*)GnTListBase<GnTObjectAllocator<T>, 
        T>::m_kAllocator.Allocate();
}
//---------------------------------------------------------------------------
template <class T> inline
void GnTObjectList<T>::DeleteItem(GnTListItem<T>* pkItem)
{
    GnTListBase<GnTObjectAllocator<T>, T>::m_kAllocator.Deallocate(pkItem);
}
//---------------------------------------------------------------------------
